﻿using System;

[assembly: CLSCompliant(true)]

namespace TransitionsLib
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media.Animation;

    public partial class TransitionConrol : UserControl
    {
        public static readonly DependencyProperty TransitionTypeProperty = DependencyProperty.Register(
            "TransitionType",
            typeof(PageTransitionType),
            typeof(TransitionConrol),
            new PropertyMetadata(PageTransitionType.SlideAndFade));

        public static readonly DependencyProperty StartPageProperty = DependencyProperty.Register(
            "StartPage",
            typeof(UserControl),
            typeof(TransitionConrol));

        public Dictionary<string, UserControl> Pages = new Dictionary<string, UserControl>();

        public TransitionConrol()
        {
            InitializeComponent();
        }

        private string nextPageName;

        public UserControl CurrentPage { get; set; }

        public PageTransitionType TransitionType
        {
            get
            {
                return (PageTransitionType)GetValue(TransitionTypeProperty);
            }

            set
            {
                SetValue(TransitionTypeProperty, value);
            }
        }

        public UserControl StartPage
        {
            set
            {
                SetValue(StartPageProperty, value);
                Dispatcher.Invoke((Action)delegate
                                               {
                                                   value.Loaded += this.NewPageLoaded;
                                                   contentPresenter.Content = value;
                                               });
            }
        }

        public void ShowPage(UserControl newPage, string pageName = "none")
        {
            if (this.Pages.All(page => page.Key != pageName))
            {
                this.Pages.Add(pageName, newPage);
            }

            nextPageName = pageName;
            Task.Factory.StartNew(ShowNewPage);
        }

        void ShowNewPage()
        {
            Dispatcher.BeginInvoke((Action)delegate 
            {
                if (contentPresenter.Content != null)
                {
                    var oldPage = contentPresenter.Content as UserControl;
                    if (oldPage != null)
                    {
                        oldPage.Loaded -= this.NewPageLoaded;
                        UnloadPage(oldPage);
                    }
                }
                else
                {
                    ShowNextPage(nextPageName);
                }
            });
        }

        void ShowNextPage(string pageName)
        {
            UserControl newPage;
            if (this.Pages.All(page => page.Key != pageName))
            {
                return;
            }

            newPage = this.Pages[pageName];
            newPage.Visibility = Visibility.Visible;
            newPage.Loaded += this.NewPageLoaded;
            contentPresenter.Content = newPage;
        }

        void UnloadPage(UserControl page)
        {
            var hidePage = (Resources[string.Format("{0}Out", TransitionType.ToString())] as Storyboard).Clone();
            hidePage.Completed += this.HidePageCompleted;
            hidePage.Begin(contentPresenter);
        }

        void NewPageLoaded(object sender, RoutedEventArgs e)
        {
            var showNewPage = Resources[string.Format("{0}In", TransitionType.ToString())] as Storyboard;
            showNewPage.Begin(contentPresenter);
            CurrentPage = sender as UserControl;
            var collpages = Pages.Values.Where(page => page != CurrentPage).ToArray();
            foreach (var page in collpages)
            {
                page.Visibility = Visibility.Collapsed;
            }
        }

        void HidePageCompleted(object sender, EventArgs e)
        {
            contentPresenter.Content = null;
            ShowNextPage(nextPageName);
        }
    }
}
